<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="用户授权" tabindex="-1"><a class="header-anchor" href="#用户授权"><span>用户授权</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#gates">拦截器</a>
<ul>
<li><a href="#writing-gates">编写拦截器</a></li>
<li><a href="#authorizing-actions-via-gates">授权操作</a></li>
<li><a href="#gate-responses">拦截器响应</a></li>
<li><a href="#intercepting-gate-checks">拦截拦截器检查</a></li>
<li><a href="#inline-authorization">内联授权</a></li>
</ul>
</li>
<li><a href="#creating-policies">创建策略</a>
<ul>
<li><a href="#generating-policies">生成策略</a></li>
<li><a href="#registering-policies">注册策略</a></li>
</ul>
</li>
<li><a href="#writing-policies">编写策略</a>
<ul>
<li><a href="#policy-methods">策略方法</a></li>
<li><a href="#policy-responses">策略响应</a></li>
<li><a href="#methods-without-models">无模型方法</a></li>
<li><a href="#guest-users">访客用户</a></li>
<li><a href="#policy-filters">策略过滤器</a></li>
</ul>
</li>
<li><a href="#authorizing-actions-using-policies">使用策略授权操作</a>
<ul>
<li><a href="#via-the-user-model">通过用户模型</a></li>
<li><a href="#via-the-gate-facade">通过拦截器门面</a></li>
<li><a href="#via-middleware">通过中间件</a></li>
<li><a href="#via-blade-templates">通过 Blade 模板</a></li>
<li><a href="#supplying-additional-context">提供额外上下文</a></li>
</ul>
</li>
<li><a href="#authorization-and-inertia">授权与 Inertia</a></li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<p>除了提供内置的 <a href="https://learnku.com/docs/laravel/11.x/authentication" target="_blank" rel="noopener noreferrer">身份认证 authentication</a> 服务外, Laravel 还提供了一种简单的方法来授权用户对给定资源的操作。例如， 即使用户已经通过认证，他们也可能没有被授权更新或删除某些 Eloquent 模型或应用程序管理的数据库记录。 Laravel 的授权功能提供了一种简单、有序的方式来管理这些类型的授权检查。</p>
<p>Laravel 提供了两种主要的授权操作方式：<a href="#gates">拦截器 Gates</a> 和<a href="#creating-policies">策略 Policies</a>。可以把拦截器和策略想象成路由和控制器。拦截器提供了一种基于闭包的简单授权方法，而策略则像控制器一样，围绕特定模型或资源组织逻辑。在本文档中，我们将首先探讨拦截器，然后研究策略。</p>
<p>在构建应用程序时，你不需要在仅使用拦截器和仅使用策略之间做出选择。大多数应用程序很可能会混合使用拦截器和策略，这是完全正常的！拦截器最适用于与任何模型或资源无关的操作，例如查看管理员仪表板。相反，当你希望为特定模型或资源授权某项操作时，应该使用策略。</p>
<h2 id="拦截器-gates" tabindex="-1"><a class="header-anchor" href="#拦截器-gates"><span>拦截器 (Gates)</span></a></h2>
<h3 id="编写拦截器-gates" tabindex="-1"><a class="header-anchor" href="#编写拦截器-gates"><span>编写拦截器（Gates）</span></a></h3>
<blockquote>
<p>[!注意]<br>
拦截器（Gates）是学习 Laravel 授权特性基础知识的好方法，但在构建健壮的 Laravel 应用时，应该考虑结合使用策略 <a href="#creating-policies">policies</a> 来组织授权规则。</p>
</blockquote>
<p>拦截器（Gates）是用来确定用户是否有权执行给定操作的闭包函数。通常，拦截器（Gates）通过 <code v-pre>Gate</code> 门面在 <code v-pre>App\Providers\AppServiceProvider</code> 类中的 <code v-pre>boot</code> 函数里定义。拦截器（Gates）始终接收一个用户实例作为第一个参数，可以选择性的接收额外参数，例如相关的 Eloquent 模型。</p>
<p>在下面的例子中，我们将定义一个拦截器（Gates)来确定用户是否可以更新给定的 <code v-pre>App\Models\Post</code> 模型。拦截器（Gates）将通过比较用户的 <code v-pre>id</code>与创建帖子的用户的 <code v-pre>user_id</code> 来实现该判断：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 启动任何应用程序服务.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>与控制器一样，拦截器（Gates）也可以使用类回调数组来定义：:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>PostPolicy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 启动任何应用程序服务.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostPolicy</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="授权操作" tabindex="-1"><a class="header-anchor" href="#授权操作"><span>授权操作</span></a></h3>
<p>要使用拦截器（Gates）授权操作，你应该使用 <code v-pre>Gate</code> 门面提供的 <code v-pre>allows</code> 或 <code v-pre>denies</code> 方法。注意，你不需要将当前认证的用户传递给这些方法，Laravel 会自动处理将用户传递给拦截器（gate）闭包。通常，在应用程序的控制器中，需要授权操作之前调用门面授权方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新给定的帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 更新帖子...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想确定某个指定用户是否有权执行某个操作，可以使用 <code v-pre>Gate</code> 门面的 <code v-pre>forUser</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该用户可以更新帖子...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">denies</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该用户无法更新帖子...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>any</code> 或 <code v-pre>none</code> 方法一次授权多个操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">any</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该用户可以更新或删除帖子...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">none</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该用户不能更新或删除帖子...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="授权或抛出异常" tabindex="-1"><a class="header-anchor" href="#授权或抛出异常"><span>授权或抛出异常</span></a></h4>
<p>如果你想要在尝试授权一个操作，但该用户不允许执行该操作时自动抛出 <code v-pre>Illuminate\Auth\Access\AuthorizationException</code> 异常，可以使用 <code v-pre>Gate</code> 门面的 <code v-pre>authorize</code> 方法。Laravel 会自动将 <code v-pre>AuthorizationException</code> 实例转换为 403 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 该操作已授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="提供额外上下文" tabindex="-1"><a class="header-anchor" href="#提供额外上下文"><span>提供额外上下文</span></a></h4>
<p>用于授权能力的拦截器方法（<code v-pre>allows</code>, <code v-pre>denies</code>, <code v-pre>check</code>, <code v-pre>any</code>, <code v-pre>none</code>, <code v-pre>authorize</code>, <code v-pre>can</code>, <code v-pre>cannot</code>）以及授权的 <a href="#via-blade-templates">Blade 指令</a>（<code v-pre>@can</code>, <code v-pre>@cannot</code>, <code v-pre>@canany</code>）可以接收一个数组作为它们的第二个参数。这些数组元素作为参数传递给拦截器闭包，并可以在做出授权决策时用于额外的上下文：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Category</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Category</span> <span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token keyword type-hint">bool</span> <span class="token variable">$pinned</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canPublishToGroup</span><span class="token punctuation">(</span><span class="token variable">$category</span><span class="token operator">-></span><span class="token property">group</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">elseif</span> <span class="token punctuation">(</span><span class="token variable">$pinned</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canPinPosts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token variable">$pinned</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该用户可以创建帖子...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="拦截器响应" tabindex="-1"><a class="header-anchor" href="#拦截器响应"><span>拦截器响应</span></a></h3>
<p>到目前为止，我们只考察了返回简单布尔值的拦截器。然而，有时你可能希望返回一个更详细的响应，包括错误信息。为此，你可以从你的拦截器返回一个 <code v-pre>Illuminate\Auth\Access\Response</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'您必须是管理员。'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>即使你从拦截器返回一个授权响应，<code v-pre>Gate::allows</code> 方法仍然会返回一个简单的布尔值；然而，你可以使用 <code v-pre>Gate::inspect</code> 方法来获取拦截器返回的完整授权响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该操作已授权...</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当使用 <code v-pre>Gate::authorize</code> 方法时，如果操作未被授权，则会抛出 <code v-pre>AuthorizationException</code> 异常，授权响应提供的错误信息将传播到 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 该操作已授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义-http-响应状态" tabindex="-1"><a class="header-anchor" href="#自定义-http-响应状态"><span>自定义 HTTP 响应状态</span></a></h4>
<p>当通过拦截器拒绝一个操作时，会返回一个 <code v-pre>403</code> HTTP 响应；然而，有时返回一个替代的 HTTP 状态码可能很有用。你可以使用 <code v-pre>Illuminate\Auth\Access\Response</code> 类的 <code v-pre>denyWithStatus</code> 静态构造函数来自定义授权检查失败返回的 HTTP 状态码：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyWithStatus</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>由于通过 <code v-pre>404</code> 响应隐藏资源是 Web 应用程序中的一种常见模式，因此提供了 <code v-pre>denyAsNotFound</code> 方法以方便使用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyAsNotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="拦截拦截器检查" tabindex="-1"><a class="header-anchor" href="#拦截拦截器检查"><span>拦截拦截器检查</span></a></h3>
<p>有时，你可能希望授予特定用户所有权限，你可以使用 <code v-pre>before</code> 方法来定义一个在所有其他授权检查之前运行的闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">before</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果 <code v-pre>before</code> 闭包返回一个非 null 结果，该结果将被视为授权检查的结果。</p>
<p>你可以使用 <code v-pre>after</code> 方法来定义一个在所有其他授权检查之后执行的闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">,</span> <span class="token keyword type-declaration">bool</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$result</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$arguments</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>与 <code v-pre>before</code> 方法类似，如果 <code v-pre>after</code> 闭包返回一个非 null 结果，则该结果将被视为授权检查的结果。</p>
<h3 id="内联授权" tabindex="-1"><a class="header-anchor" href="#内联授权"><span>内联授权</span></a></h3>
<p>有时，你可能希望确定当前已认证用户是否有权执行给定操作，而不编写与该操作对应的专用拦截器。Laravel 允许你通过 <code v-pre>Gate::allowIf</code> 和 <code v-pre>Gate::denyIf</code> 方法执行这些类型的「内联」授权检查。内联授权不会执行任何定义的 <a href="#intercepting-gate-checks">「before」或「after」 授权钩子</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allowIf</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">denyIf</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">banned</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果操作未被授权或当前没有用户认证，Laravel 将自动抛出 <code v-pre>Illuminate\Auth\Access\AuthorizationException</code> 异常。<code v-pre>AuthorizationException</code> 实例会自动被 Laravel 的异常处理器转换为 403 HTTP 响应。</p>
<h2 id="创建策略" tabindex="-1"><a class="header-anchor" href="#创建策略"><span>创建策略</span></a></h2>
<h3 id="生成策略" tabindex="-1"><a class="header-anchor" href="#生成策略"><span>生成策略</span></a></h3>
<p>策略是围绕特定模型或资源组织授权逻辑的类。例如，如果你的应用程序是一个博客，您可能会有一个 <code v-pre>App\Models\Post</code> 模型和一个相应的 <code v-pre>App\Policies\PostPolicy</code> 来授权用户操作，如创建或更新帖子。</p>
<p>你可以使用 <code v-pre>make:policy</code> Artisan 命令生成一个策略。生成的策略将放置在 <code v-pre>app/Policies</code> 目录中。如果该目录在你的应用程序中不存在，Laravel 将为你创建它：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:policy PostPolicy</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>make:policy</code> 命令将生成一个空的策略类，如果你希望生成一个包含与查看、创建、更新和删除资源相关的示例策略方法的类，你可以在执行命令时提供 <code v-pre>--model</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:policy PostPolicy <span class="token parameter variable">--model</span><span class="token operator">=</span>Post</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="注册策略" tabindex="-1"><a class="header-anchor" href="#注册策略"><span>注册策略</span></a></h3>
<h4 id="策略发现" tabindex="-1"><a class="header-anchor" href="#策略发现"><span>策略发现</span></a></h4>
<p>默认情况下，只要模型和策略遵循标准的 Laravel 命名约定，Laravel 就会自动发现策略。具体来说，策略必须位于包含模型的目录或其上级的 <code v-pre>Policies</code> 目录中。例如，模型可以放置在 <code v-pre>app/Models</code> 目录中，而策略可以放置在 <code v-pre>app/Policies</code> 目录中。在这种情况下，Laravel 将首先在 <code v-pre>app/Models/Policies</code> 目录中检查策略，然后在 <code v-pre>app/Policies</code> 目录中检查。此外，策略名称必须与模型名称匹配，并带有 <code v-pre>Policy</code> 后缀。因此，<code v-pre>User</code> 模型将对应于 <code v-pre>UserPolicy</code> 策略类。</p>
<p>如果你想要定义自己的策略发现逻辑，可以使用 <code v-pre>Gate::guessPolicyNamesUsing</code> 方法注册一个自定义策略发现回调。通常，此方法应在应用程序的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">guessPolicyNamesUsing</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$modelClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 返回给定模型策略类的名称...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="手动注册策略" tabindex="-1"><a class="header-anchor" href="#手动注册策略"><span>手动注册策略</span></a></h4>
<p>使用 <code v-pre>Gate</code> 门面，你可以在应用程序的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中手动注册策略及其对应的模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>OrderPolicy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 启动任何应用程序服务</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">policy</span><span class="token punctuation">(</span><span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name static-context">OrderPolicy</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="编写策略" tabindex="-1"><a class="header-anchor" href="#编写策略"><span>编写策略</span></a></h2>
<h3 id="策略方法" tabindex="-1"><a class="header-anchor" href="#策略方法"><span>策略方法</span></a></h3>
<p>一旦策略类被注册，你可以为每个它授权的操作添加方法。例如，让我们在 <code v-pre>PostPolicy</code> 上定义一个 <code v-pre>update</code> 方法，该方法确定给定的 <code v-pre>App\Models\User</code> 是否可以更新给定的 <code v-pre>App\Models\Post</code> 实例。</p>
<p><code v-pre>update</code> 方法将接收一个 <code v-pre>User</code> 和一个 <code v-pre>Post</code> 实例作为其参数，并应返回 <code v-pre>true</code> 或 <code v-pre>false</code> 以指示用户是否有权更新给定的 <code v-pre>Post</code>。因此，在这个例子中，我们将验证用户的 <code v-pre>id</code> 与帖子上的 <code v-pre>user_id</code> 是否匹配：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以根据需要继续在策略上定义其他方法，以授权各种操作。例如，你可以定义 <code v-pre>view</code> 或 <code v-pre>delete</code> 方法来授权各种与 <code v-pre>Post</code> 相关的操作，但请记住，策略方法的命名，可以随心所欲。</p>
<p>如果你在通过 Artisan 控制台生成策略时使用了 <code v-pre>--model</code> 选项，它已经包含 <code v-pre>viewAny</code>、 <code v-pre>view</code>、 <code v-pre>create</code>、 <code v-pre>update</code>、 <code v-pre>delete</code>、 <code v-pre>restore</code> 和 <code v-pre>forceDelete</code> 操作的方法。</p>
<blockquote>
<p>[!注意]<br>
所有策略都通过 Laravel <a href="https://learnku.com/docs/laravel/11.x/container" target="_blank" rel="noopener noreferrer">服务容器</a> 解析，允许你在策略的构造函数中键入所需的任何依赖项，以便自动注入它们。</p>
</blockquote>
<h3 id="策略响应" tabindex="-1"><a class="header-anchor" href="#策略响应"><span>策略响应</span></a></h3>
<p>目前为止，我们只考察了返回简单布尔值的策略方法。然而，有时你可能希望返回一个更详细的响应，包括错误信息。为此，你可以从策略方法返回一个 <code v-pre>Illuminate\Auth\Access\Response</code> 实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'您不拥有该篇文章。'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当从策略返回一个授权响应时，<code v-pre>Gate::allows</code> 方法仍然会返回一个简单的布尔值；然而，您可以使用 <code v-pre>Gate::inspect</code> 方法来获取拦截器返回的完整授权响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 该操作已授权...</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当使用 <code v-pre>Gate::authorize</code> 方法时，如果操作未被授权，则会抛出 <code v-pre>AuthorizationException</code> 异常，授权响应提供的错误信息将传播到 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 该操作已授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义-http-响应状态-1" tabindex="-1"><a class="header-anchor" href="#自定义-http-响应状态-1"><span>自定义 HTTP 响应状态</span></a></h4>
<p>当通过策略方法拒绝一个操作时，会返回一个 <code v-pre>403</code> HTTP 响应；然而，有时返回一个替代的 HTTP 状态码可能很有用。你可以使用 <code v-pre>Illuminate\Auth\Access\Response</code> 类的 <code v-pre>denyWithStatus</code> 静态构造函数来自定义失败授权检查返回的 HTTP 状态码：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyWithStatus</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>由于通过 <code v-pre>404</code> 响应隐藏资源是 Web 应用程序中的一种常见模式，因此提供了 <code v-pre>denyAsNotFound</code> 方法以方便使用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyAsNotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="无模型方法" tabindex="-1"><a class="header-anchor" href="#无模型方法"><span>无模型方法</span></a></h3>
<p>某些策略方法只接收当前认证用户的实例。这种情况在授权 <code v-pre>create</code> 操作时最为常见。例如，如果你正在创建一个博客，你可能希望确定用户是否有权创建任何帖子。在这些情况下，你的策略方法应该只期望接收一个用户实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定给定用户是否可以创建帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">role</span> <span class="token operator">==</span> <span class="token string single-quoted-string">'writer'</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="访客用户" tabindex="-1"><a class="header-anchor" href="#访客用户"><span>访客用户</span></a></h3>
<p>默认情况下，如果传入的 HTTP 请求不是由认证用户发起的，所有拦截器和策略会自动返回 <code v-pre>false</code>。然而，你可以通过声明一个「可选」类型提示或在用户参数定义中提供一个 <code v-pre>null</code> 默认值，来允许这些授权检查传递给你的拦截器和策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">?-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="策略过滤器" tabindex="-1"><a class="header-anchor" href="#策略过滤器"><span>策略过滤器</span></a></h3>
<p>对于特定用户，你可能想要在给定策略中授权所有操作。为此，请在策略上定义一个 <code v-pre>before</code> 方法。<code v-pre>before</code> 方法将在策略上的任何其他方法之前执行，让你有机会在实际调用目标策略方法之前授权操作。此功能最常用于授权应用程序管理员执行任何操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行预授权检查。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">before</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token constant">null</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要拒绝特定类型用户的所有授权检查，则可以从 <code v-pre>before</code> 方法返回 <code v-pre>false</code>。如果返回 <code v-pre>null</code>，授权检查将通过策略方法执行。</p>
<blockquote>
<p>[!警告]<br>
如果策略类不包含与正在检查的权限名称匹配的方法，则不会调用该类的 <code v-pre>before</code> 方法。</p>
</blockquote>
<h2 id="使用策略授权操作" tabindex="-1"><a class="header-anchor" href="#使用策略授权操作"><span>使用策略授权操作</span></a></h2>
<h3 id="通过用户模型" tabindex="-1"><a class="header-anchor" href="#通过用户模型"><span>通过用户模型</span></a></h3>
<p>Laravel 应用程序中包含的 <code v-pre>App\Models\User</code> 模型提供了两个有用的方法来授权操作：<code v-pre>can</code> 和 <code v-pre>cannot</code>。<code v-pre>can</code> 和 <code v-pre>cannot</code> 方法接收你想要授权的操作名称和相关模型。例如，让我们确定用户是否有权更新给定的 <code v-pre>App\Models\Post</code> 模型。通常，这将在控制器方法中完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新指定的帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 更新帖子...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果为给定模型<a href="#registering-policies">注册了策略</a>，<code v-pre>can</code> 方法将自动调用适当的策略并返回布尔结果。如果没有为模型注册策略，<code v-pre>can</code> 方法将尝试调用与给定操作名称匹配的基于闭包的拦截器。</p>
<h4 id="不需要模型的操作" tabindex="-1"><a class="header-anchor" href="#不需要模型的操作"><span>不需要模型的操作</span></a></h4>
<p>请记住，某些操作可能对应于策略方法不需要模型实例，如 <code v-pre>create</code>。在这些情况下，你可以将类名传递给 <code v-pre>can</code> 方法，类名将用于确定授权操作时要使用的策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 创建该帖子...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过-gate-门面" tabindex="-1"><a class="header-anchor" href="#通过-gate-门面"><span>通过 <code v-pre>Gate</code> 门面</span></a></h3>
<p>除了为 <code v-pre>App\Models\User</code> 模型提供的实用方法外，你始终可以通过 <code v-pre>Gate</code> 门面的 <code v-pre>authorize</code> 方法来授权操作。</p>
<p>与 <code v-pre>can</code> 方法类似，此方法接收你想要授权的操作名称和相关模型。如果操作未被授权，<code v-pre>authorize</code> 方法将抛出 <code v-pre>Illuminate\Auth\Access\AuthorizationException</code> 异常，Laravel 异常处理器会自动将其转换为带有 403 状态码的 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新给定的博客文章。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 当前用户可以更新该博客文章...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要模型的操作-1" tabindex="-1"><a class="header-anchor" href="#不需要模型的操作-1"><span>不需要模型的操作</span></a></h4>
<p>如前所述，某些策略方法（如 <code v-pre>create</code>）不需要模型实例。在这些情况下，你应该将类名传递给 <code v-pre>authorize</code> 方法，类名将用于确定授权操作时要使用的策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 创建一篇新的博客文章。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 当前用户可以创建博客文章...</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过中间件" tabindex="-1"><a class="header-anchor" href="#通过中间件"><span>通过中间件</span></a></h3>
<p>Laravel 包含一个中间件，可以在传入请求到达您的路由或控制器之前授权操作。默认情况下，<code v-pre>Illuminate\Auth\Middleware\Authorize</code> 中间件可以通过 <code v-pre>can</code> <a href="https://learnku.com/docs/laravel/11.x/middleware#middleware-alias" target="_blank" rel="noopener noreferrer">中间件别名</a>附加到路由，该别名由 Laravel 自动注册。让我们探索一个使用 <code v-pre>can</code> 中间件授权用户可以更新帖子的示例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{post}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新该帖子...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:update,post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个例子中，我们向 <code v-pre>can</code> 中间件传递了两个参数。第一个是我们想要授权的操作名称，第二个是我们想要传递给策略方法的路由参数。在这种情况下，由于我们使用了<a href="https://learnku.com/docs/laravel/11.x/routing#implicit-binding" target="_blank" rel="noopener noreferrer">隐式模型绑定</a>，一个 <code v-pre>App\Models\Post</code> 模型将被传递给策略方法。如果用户未被授权执行给定操作，中间件将返回一个带有 403 状态码的 HTTP 响应。</p>
<p>为了方便起见，你还可以使用 <code v-pre>can</code> 方法将 <code v-pre>can</code> 中间件附加到路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{post}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新该帖子...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要模型的操作-2" tabindex="-1"><a class="header-anchor" href="#不需要模型的操作-2"><span>不需要模型的操作</span></a></h4>
<p>同样，某些策略方法（如 <code v-pre>create</code>）不需要模型实例。在这些情况下，你可以将类名传递给中间件。类名将用于确定授权操作时要使用的策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建帖子...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:create,App\Models\Post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在字符串中间件定义中指定整个类名可能会变得繁琐，因此，你可以选择使用 <code v-pre>can</code> 方法将 <code v-pre>can</code> 中间件附加到路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建帖子...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过-blade-模板" tabindex="-1"><a class="header-anchor" href="#通过-blade-模板"><span>通过 Blade 模板</span></a></h3>
<p>在编写 Blade 模板时，你可能希望仅在用户有权执行给定操作时显示页面的某部分。例如，你可能希望仅在用户实际上可以更新博客帖子时显示更新表单。在这种情况下，你可以使用 <code v-pre>@can</code> 和 <code v-pre>@cannot</code> 指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@can('update', $post)</span>
<span class="line">    &lt;!-- 当前用户可以更新帖子... --&gt;</span>
<span class="line">@elsecan('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可以创建新的帖子... --&gt;</span>
<span class="line">@else</span>
<span class="line">    &lt;!-- ... --&gt;</span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@cannot('update', $post)</span>
<span class="line">    &lt;!-- 当前用户无法更新帖子... --&gt;</span>
<span class="line">@elsecannot('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户不能创建新帖子... --&gt;</span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这些指令是编写 <code v-pre>@if</code> 和 <code v-pre>@unless</code> 语句的便捷快捷方式,上面的 <code v-pre>@can</code> 和 <code v-pre>@cannot</code> 语句等同于以下语句：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if (Auth::user()-&gt;can('update', $post))</span>
<span class="line">    &lt;!-- 当前用户可以更新帖子... --&gt;</span>
<span class="line">@endif</span>
<span class="line"></span>
<span class="line">@unless (Auth::user()-&gt;can('update', $post))</span>
<span class="line">    &lt;!-- 当前用户无法更新帖子... --&gt;</span>
<span class="line">@endunless</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以确定用户是否有权从给定操作数组中执行任何操作，为此，请使用 <code v-pre>@canany</code> 指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@canany(['update', 'view', 'delete'], $post)</span>
<span class="line">    &lt;!-- 当前用户可以更新、查看或删除帖子... --&gt;</span>
<span class="line">@elsecanany(['create'], \App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可以创建帖子... --&gt;</span>
<span class="line">@endcanany</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要模型的操作-3" tabindex="-1"><a class="header-anchor" href="#不需要模型的操作-3"><span>不需要模型的操作</span></a></h4>
<p>与大多数其他授权方法一样，如果操作不需要模型实例，你可以将类名传递给 <code v-pre>@can</code> 和 <code v-pre>@cannot</code> 指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@can('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可以创建帖子... --&gt;</span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@cannot('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户不能创建帖子... --&gt;</span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="提供额外上下文-1" tabindex="-1"><a class="header-anchor" href="#提供额外上下文-1"><span>提供额外上下文</span></a></h3>
<p>在使用策略授权操作时，你可以将数组作为各种授权函数和辅助函数的第二个参数传递。数组中的第一个元素将用于确定应调用哪个策略，而数组中的其余元素将作为参数传递给策略方法，并可以在做出授权决策时用于额外的上下文。例如，考虑以下包含额外 <code v-pre>$category</code> 参数的 <code v-pre>PostPolicy</code> 方法定义：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token keyword type-hint">int</span> <span class="token variable">$category</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span> <span class="token operator">&amp;&amp;</span></span>
<span class="line">           <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canUpdateCategory</span><span class="token punctuation">(</span><span class="token variable">$category</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当尝试确定认证用户是否可以更新给定的帖子时，我们可以这样调用策略方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 更新给定的博客文章。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token property">category</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 当前用户可以更新博客文章...</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="授权与-inertia" tabindex="-1"><a class="header-anchor" href="#授权与-inertia"><span>授权与 Inertia</span></a></h2>
<p>虽然授权必须总是在服务器上处理，但提供前端应用程序授权数据以正确渲染应用程序的 UI 通常很方便。Laravel 没有定义将授权信息暴露给 Inertia 驱动的前端所需的约定。</p>
<p>然而，如果你使用的是 Laravel 的基于 Inertia 的 <a href="https://learnku.com/docs/laravel/11.x/starter-kits" target="_blank" rel="noopener noreferrer">入门套件</a>，你的应用程序已经包含一个 <code v-pre>HandleInertiaRequests</code> 中间件。在这个中间件的 <code v-pre>share</code> 方法中，你可以返回将提供给应用程序中所有 Inertia 页面的共享数据，这些共享数据可以作为为用户定义授权信息的便捷位置：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Inertia<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">HandleInertiaRequests</span> <span class="token keyword">extends</span> <span class="token class-name">Middleware</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 定义默认情况下共享的属性。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;string, mixed></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">share</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token operator">...</span><span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">share</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'auth'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'user'</span> <span class="token operator">=></span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'permissions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                        <span class="token string single-quoted-string">'create'</span> <span class="token operator">=></span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/authorizationmd/16691" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/au...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/authorizationmd/16691" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/au...</a></p>
</blockquote>
</div></template>


